package myJs

import japgolly.scalajs.react.vdom.all.s

import scala.collection.immutable.SeqMap
import scala.scalajs.js
import scala.scalajs.js.JSON
import myJs.Implicits._
import myJs.Utils.layer
import myJs.myPkg.{ColumnOptions, ExportOptions, LayerOptions, Select2Options, TableOptions, TypeaheadOptions}
import scalatags.Text.all._

import scala.scalajs.js.JSConverters._
import myJs.myPkg.jquery._
import myJs.tool.Tool
import org.scalajs.dom.{Element, document}
import org.scalajs.dom.ext.Ajax
import shared.VarTool

import js.Dynamic.{global => g}
import scala.concurrent.ExecutionContext.Implicits.global

/**
 * Created by yz on 6/5/2021
 */
object CircRnaBrowse {

  val tabId = "circRna"
  val tableId = "table"
  val formId = "form"
  val formJq = $(s"#${tabId} #${formId}")
  val tableJq = $(s"#${tabId} #${tableId}")

  def init = {
    refreshChr
    registerEvent
    refreshSampleTypes.zip(refreshGeneSymbol).zip(refreshDiffGroup).map { x =>
      bootStrapValidator
      initTable()
    }
  }

  def refreshDiffGroup = {
    val url = g.jsRoutes.controllers.CircRnaController.getAllDiffGroup().url.toString
    Ajax.get(url = s"${url}").map { xhr =>
      val data = JSON.parse(xhr.responseText).toJArS
      val array = data.map { kind =>
        js.Dictionary("text" -> kind, "id" -> kind)
      }
      val options = Select2Options.multiple(true).allowClear(true).placeholder("click to choose").dictData(array)
      $(s"#${tabId}").findInputByName("diffSamples[]").select2(options)
    }
  }

  def refreshGeneSymbol = {
    val url = g.jsRoutes.controllers.BrowseController.getAllGeneSymbols().url.toString
    Ajax.get(url = s"${url}").map { xhr =>
      val data = JSON.parse(xhr.responseText).toJArS
      Tool.getInputByName("geneName").typeahead("destroy").typeahead(TypeaheadOptions.source(data)
        .highlighter(Tool.highlighterF).updater(Tool.singleUpdater).matcher(Tool.matcher))
    }
  }

  def registerEvent = {
    $(document.body).on("click", s"#${tabId} .mySearch", "", (y: Element) => {
      mySearch
    })
    $(document.body).on("change", s"#${tabId} .myChr", "", (y: Element) => {
      val myValue = $(y).find(">option:selected").`val`().toString
      myValue match {
        case "all" => $("#start,#end").attr("disabled", true)
        case _ => $("#start,#end").attr("disabled", false)
      }
    })
    $(document.body).on("change", s"#${tabId} .myGeneSymbol", "", (y: Element) => {
      val myValue = $(y).find(">option:selected").`val`().toString
      myValue match {
        case "na" => $("#geneName").attr("disabled", true).`val`("")
        case _ => $("#geneName").attr("disabled", false)
      }
    })
  }

  def mySearch = {
    val formJq = $(s"#${tabId} #${formId}")
    val bv = formJq.bv
    bv.validate()
    val valid = bv.isValid()
    if (valid) {
      val element = div(id := "content",
        span(id := "info", "searching...",
          span(id := "progress", "。。。")), " ",
        img(src := "/assets/images/running2.gif", cls := "runningImage", width := 30, height := 20)
      ).render
      val layerOptions = LayerOptions.title(Tool.zhInfo).closeBtn(0).skin("layui-layer-molv").btn(js.Array())
      val index = layer.alert(element, layerOptions)
     tableJq.bootstrapTable("refresh")
      layer.close(index)
    }
  }

  def refreshSampleTypes = {
    val url = g.jsRoutes.controllers.BrowseController.getCircRnaSampleTypes().url.toString
    Ajax.get(url = s"${url}").map { xhr =>
      val data = JSON.parse(xhr.responseText).toJArS
      val array = data.map { kind =>
        js.Dictionary("text" -> kind, "id" -> kind)
      }
      val options = Select2Options.multiple(true).allowClear(true).placeholder("click to choose").dictData(array)
      $(s"#${tabId}").findInputByName("samples[]").select2(options)
    }
  }

  def refreshChr = {
    val chrArray = List("all", "Chr1", "Chr2", "Chr3", "Chr4", "Chr5", "Chr6", "Chr7", "Chr8", "Chr9", "Chr10",
      "Chr11", "Chr12", "Chr13", "Chr14", "Chr15", "Chr16", "Chr17", "Chr18", "Chr19", "Chr20",
      "Chr21", "Chr22", "ChrX", "ChrY")
    val html = chrArray.map { v =>
      option(value := v, v)
    }.mkString
    $(s"#${tabId}").findInputByName("chr").html(html)
  }

  def tbFmt(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[js.Any]) => {
    columnName match {
      case "chromosome" =>
        s"${row("chromosome")}:${row("start")}-${row("end")}"
      case "circId" =>
        val url = g.jsRoutes.controllers.DetailController.detailInfo().url.toString
        a(href := s"${url}?id=${v}&kind=${VarTool.circRnaKind}", target := "_blank", v.toString)
      case "circBaseId" =>
        if (v.toString.toUpperCase == "NA") {
          v.toString
        } else {
          val url = s"http://www.circbase.org/cgi-bin/singlerecord.cgi?id=${v}"
          a(href := s"${url}", target := "_blank", v.toString)
        }
      case "geneSymbol" =>
        val url = g.jsRoutes.controllers.DetailController.detailInfo().url.toString
        a(href := s"${url}?id=${v}&kind=${VarTool.mRnaKind}", target := "_blank", v.toString)
      case _ => v
    }
  }

  def expStyle(columnName: String): js.Function = (v: js.Any, row: js.Dictionary[Any]) => columnName match {
    case _ => v
  }

  val plotColumn = js.Array(
    ColumnOptions.field("operate").title("Plot").formatter(plotFmt).filterControl("clear")
  )

  def plotFmt: js.Function = {
    (v: js.Any, row: js.Dictionary[js.Any]) =>
      val url = g.jsRoutes.controllers.DetailController.detailInfo().url.toString
      a(href := s"${url}?id=${row("circId")}&kind=${VarTool.circRnaKind}&tab=${VarTool.profileTabId}", target := "_blank", `class` := "myBlood",
        span(cls := "fa fa-picture-o")
      )

  }

  def onSort:js.Function=(name:String,order:String)=>{
    tableJq.bootstrapTable("refresh")
  }

  def initTable(tableJq: JQuery = $(s"#${tabId} #${tableId}"),isServerSide: Boolean = true) = {
    val map = VarTool.circRnaMap
    val columnNames = map.keyList
    val columns = columnNames.map { columnName =>
      val title = map.getOrElse(columnName, columnName)
      val fmt = tbFmt(columnName)
      val style = expStyle(columnName)
      val basicOptions = ColumnOptions.field(columnName).title(title).titleTooltip(title).sortable(true).formatter(fmt).cellStyle(style)
      columnName match {
        case "circBaseId" =>
          val thClass = "myCircBaseIdSortTh"
          basicOptions.`class`(thClass)
        case _ => basicOptions
      }
    }.concat(plotColumn)
    val exportOptions = ExportOptions.fileName("data")
    val basicOptions = TableOptions.columns(columns.toJSArray).searchOnButton(false).filterControl(false).
      exportOptions(exportOptions).exportTypes(js.Array("csv")).showExport(true).exportDataType("all")
    val options = if (isServerSide) {
      basicOptions.method("post").sidePagination("server").ajax(ajaxRequest).onSort(onSort)
    } else basicOptions
    tableJq.bootstrapTable(options)

    if(isServerSide){
      $(s"#${tabId} li[data-type='csv']").off("click").on("click", () => {
        val index = layer.alert(Tool.loadingElement, Tool.layerOptions)
        val ids = tableJq.bootstrapTable("getData", js.Dictionary("useCurrentPage" -> true)).
          toJArJDS.map { x =>
          x("circId")
        }
        val dict = Map(
          "ids" -> ids
        ).toJSDictionary
        val url = g.jsRoutes.controllers.CircRnaController.downloadAll().url.toString
        Ajax.post(url = s"${url}", data = JSON.stringify(dict), headers = Map("Content-Type" -> "application/json"),
          responseType = "blob").map {
          xhr =>
            layer.close(index)
            Tool.downloadCsv(s"data.csv", xhr.response)
        }
      })
    }

  }

  def ajaxRequest: js.Function = (params: js.Dictionary[js.Any]) => {
    val url = g.jsRoutes.controllers.CircRnaController.searchAllByServer().url.toString
    val dataJson = params("data").toString.toJDJAn
    val pageDataStr = $.param(dataJson)
    val formData = formJq.serialize()
    Ajax.post(url = s"${url}", data = s"${formData}&${pageDataStr}",
      headers = Map("Content-Type" -> "application/x-www-form-urlencoded"),
      responseType = "application/json").map { xhr =>
      val json = xhr.responseText.toJDJAn
      val successF = params("success").asInstanceOf[js.Function1[js.Any, js.Any]]
      successF(json)
    }
  }

  def bootStrapValidator = {
    val maxNumber = Double.MaxValue
    val dict = js.Dictionary(
      "feedbackIcons" -> js.Dictionary(
        "valid" -> "glyphicon glyphicon-ok",
        "invalid" -> "glyphicon glyphicon-remove",
        "validating" -> "glyphicon glyphicon-refresh",
      ),
      "fields" -> {
        js.Dictionary(
          "start" -> js.Dictionary(
            "validators" -> js.Dictionary(
              "integer" -> js.Dictionary(
                "message" -> "position start must be an integer！",
              ),
              "between" -> js.Dictionary(
                "min" -> 1,
                "max" -> maxNumber,
                "message" -> "position start must be greater than 0！",
              ),
            )
          ),
          "end" -> js.Dictionary(
            "validators" -> js.Dictionary(
              "integer" -> js.Dictionary(
                "message" -> "position end must be an integer！",
              ),
              "between" -> js.Dictionary(
                "min" -> "start",
                "max" -> maxNumber,
                "message" -> "position end must be greater than start！",
              ),
            )
          ),
          "dfMin" -> js.Dictionary(
            "validators" -> js.Dictionary(
              "numeric" -> js.Dictionary(
                "message" -> "Detection frequency's min value be an numeric！",
              ),
              "between" -> js.Dictionary(
                "min" -> 0,
                "max" -> 1,
                "message" -> "Detection frequency's min must be between 0 and 1！",
              ),
            )
          ),
          "dfMax" -> js.Dictionary(
            "validators" -> js.Dictionary(
              "numeric" -> js.Dictionary(
                "message" -> "Detection frequency's max value be an numeric！",
              ),
              "between" -> js.Dictionary(
                "min" -> "dfMin",
                "max" -> 1,
                "message" -> "Detection frequency's max must be between the min value and 1！",
              ),
            )
          ),
        )
      }
    )
    g.$(s"#${tabId} #${formId}").bootstrapValidator(dict)
  }


}
